/*
* Copyright (C) 2012-2014 qar
* License: http://www.gnu.org/licenses/gpl.html GPL version 2
*/

#include "crypto/ciphers/encryptorsalsa20.h"
#include "crypto/ciphers/salsa20.h"
#include "crypto/ciphers/common.h"

EncryptorSalsa20::EncryptorSalsa20(QByteArray aKey, QByteArray aIv)
	: key(aKey), iv(aIv)
{
	if (key.length() < keySize()) {
		exit(1);
	}
	key.resize(keySize());
	ctx = new (struct salsa20_ctx);
	memset(ctx, 0, sizeof(*ctx));
	if (iv.isEmpty()) {
		iv.resize(SALSA20_IV_SIZE);
		generate_random_iv((u8*)iv.data(), iv.length());
	}
	salsa20_init_context(ctx, (const u8*)key.constData(), (const u8*)iv.constData());
}

EncryptorSalsa20::~EncryptorSalsa20()
{
	key.fill(0, key.length());
	iv.fill(0, iv.length());
	memset(ctx, 0, sizeof(*ctx));
	delete ctx;
	ctx = NULL;
}

qint64 EncryptorSalsa20::blockSize() const
{
	return SALSA20_BLOCK_SIZE;
}

qint64 EncryptorSalsa20::keySize() const
{
	return SALSA20_KEYSIZE;
}

QString EncryptorSalsa20::getAlgorithmName() const
{
	return "SALSA20-256";
}

void EncryptorSalsa20::encrypt(const QByteArray &clearText, QByteArray &cipherText)
{
	cipherText.resize(clearText.length());
	salsa20_encrypt_buffer(ctx, (u8*)cipherText.data(), (const u8*)clearText.constData(), clearText.length());
}

void EncryptorSalsa20::decrypt(const QByteArray &cipherText, QByteArray &clearText)
{
	clearText.resize(cipherText.length());
	salsa20_decrypt_buffer(ctx, (u8*)clearText.data(), (const u8*)cipherText.constData(), cipherText.length());
}

bool EncryptorSalsa20::toStream(QDataStream &s)
{
	s << iv;

	return s.status() == QDataStream::Ok;
}

bool EncryptorSalsa20::fromStream(QDataStream &s) {
	s >> iv;
	if (s.status() != QDataStream::Ok)
		return false;
	if (iv.length() != SALSA20_IV_SIZE)
		return false;
	salsa20_init_context(ctx, (const u8*)key.constData(), (const u8*)iv.constData());
	return true;
}
